import abc
import datetime
import struct
import zlib

from ..constants import RSP_HEADER_LEN, DEBUG
from ..exceptions import ResponseHeaderRecvFails
from ..exceptions import ResponseRecvFails
from ..exceptions import SendPkgNotReady
from ..exceptions import SendRequestPkgFails
from ..exceptions import SocketClientNotReady
from ..logger import log


class BaseParser(metaclass=abc.ABCMeta):

    def __init__(self, client, lock=None):
        """
        构造函数
        :param client:
        :param lock:
        """
        self.client = client

        self.data = None
        self.send_pkg = None

        self.rsp_header = None
        self.rsp_body = None
        self.rsp_header_len = RSP_HEADER_LEN

        self.lock = lock if lock else None

    def setParams(self, *args, **kwargs):
        """
        构建请求

        :param args:
        :param kwargs:
        """
        pass

    def parseResponse(self, body_buf):
        """
        解析应答
        :param body_buf:
        """
        return body_buf

    def setup(self):
        """ 初始配置 """
        pass

    def call_api(self):

        if self.lock:
            with self.lock:
                log.debug('sending thread lock api call')
                return self._call_api()

        return self._call_api()

    def _call_api(self):
        """

        :return:
        """
        self.setup()

        if not self.client:
            raise SocketClientNotReady('socket client not ready')

        if not self.send_pkg:
            raise SendPkgNotReady('send pkg not ready')

        # 发送请求包到服务器，返回长度
        ns_ended = self.client.send(self.send_pkg)

        # 发送包个数
        self.client.send_pkg_num += 1

        # 发送包比特值长度
        self.client.send_pkg_bytes += ns_ended

        # 最后发送比特值长度
        self.client.last_api_send_bytes = ns_ended

        # 发送包开始时间
        if self.client.first_pkg_send_time is None:
            self.client.first_pkg_send_time = datetime.datetime.now()

        if DEBUG:
            log.debug('send package:' + str(self.send_pkg))

        # 发送服务器返回内容长度不同则报错
        if ns_ended != len(self.send_pkg):
            log.debug('send bytes error')
            raise SendRequestPkgFails('send fails')

        # 接收服务器返回数据
        head_buf = self.client.recv(self.rsp_header_len)

        # debug 打印日志
        DEBUG and log.debug('recv head_buf:' + str(head_buf) + ' | len is :' + str(len(head_buf)))

        if len(head_buf) == self.rsp_header_len:
            # 接返回包数
            self.client.recv_pkg_num += 1

            # 接返回包长度
            self.client.recv_pkg_bytes += self.rsp_header_len

            # 二进制解码
            _, _, _, zip_size, unzip_size = struct.unpack('<IIIHH', head_buf)

            # 打印日志
            DEBUG and log.debug('zip size is: ' + str(zip_size))

            # 初始化 body buff
            body_buf = bytearray()

            # 最后接收数据长度
            last_api_recv_bytes = self.rsp_header_len

            # 接收 body 内容
            while True:
                buf = self.client.recv(zip_size)
                len_buf = len(buf)

                self.client.recv_pkg_num += 1
                self.client.recv_pkg_bytes += len_buf

                last_api_recv_bytes += len_buf
                body_buf.extend(buf)

                # buf 空, buf 长度 == 8 或者 buff 长度等于 zip 大小
                if not buf or len_buf == 0 or len(body_buf) == zip_size:
                    break

            # 统计数据
            self.client.last_api_recv_bytes = last_api_recv_bytes

            if len(buf) == 0:
                log.warning('接收数据体失败服务器断开连接')
                raise ResponseRecvFails('接收数据体失败服务器断开连接')

            if zip_size == unzip_size:
                log.debug('接收数据不需要解压')
            else:
                log.debug('接收数据需要解压')
                body_buf = zlib.decompress(body_buf)

            if DEBUG:
                log.debug('recv body: ')
                log.debug(body_buf)

            return self.parseResponse(body_buf)

        log.debug('head_buf is not 0x10')
        raise ResponseHeaderRecvFails(f'head_buf is not 0x10 : {head_buf}')
